/*
    Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "Program.h"
#include <D3Dcompiler.h>
#include "../utility/utility.h"

namespace SkyEngine2d
{

    Program::Program()
        : m_vertexShader(nullptr), m_pixelShader(nullptr), m_inputLayout(nullptr)
    {
    }

    Program::~Program()
    {
    }

    void Program::use(ID3D11DeviceContext *device_context)
    {
        if (this != sm_currentProgram)
        {
            sm_currentProgram = this;

            device_context->IASetInputLayout(m_inputLayout.Get());
            device_context->VSSetShader(m_vertexShader.Get(), 0, 0);
            device_context->PSSetShader(m_pixelShader.Get(), 0, 0);
        }
    }

    bool Program::compileShader(ID3D11Device *device, const D3D11_INPUT_ELEMENT_DESC *input_element_desc, UINT num_element, const char *code_byte, int code_byte_size)
    {
        DWORD shaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined(DEBUG) || defined(_DEBUG)
        shaderFlags |= D3D10_SHADER_DEBUG;
        shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;
#endif

        Microsoft::WRL::ComPtr<ID3DBlob> err_msg = nullptr;
        Microsoft::WRL::ComPtr<ID3DBlob> blob = nullptr;

        try
        {
            checkFailed(
                D3DCompile(code_byte, code_byte_size, nullptr, nullptr, nullptr, "vs_main", "vs_4_0", shaderFlags, 0, blob.GetAddressOf(), err_msg.GetAddressOf()), "编译顶点shander失败");
            checkFailed(
                device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, m_vertexShader.GetAddressOf()), "创建顶点着色器失败");

            checkFailed(
                device->CreateInputLayout(input_element_desc, num_element, blob->GetBufferPointer(), blob->GetBufferSize(), m_inputLayout.GetAddressOf()), "创建输入布局失败");

            checkFailed(
                D3DCompile(code_byte, code_byte_size, nullptr, nullptr, nullptr, "ps_main", "ps_4_0", shaderFlags, 0, blob.ReleaseAndGetAddressOf(), err_msg.ReleaseAndGetAddressOf()), "编译像素着色器失败");
            checkFailed(
                device->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, m_pixelShader.GetAddressOf()), "创建像素着色器失败");
        }
        catch (const std::exception &e)
        {
            MessageBoxA(0, e.what(), 0, 0);
            return false;
        }
        return true;
    }

    Program *Program::sm_currentProgram = nullptr;

}
